mov ax,cs                                       ;把代码段寄存器的基地址赋值给ax
mov ss,ax                                       ;ss = cs
mov sp,0x7c00                                   ;sp = 0x7c00

mov ax,[cs:gdt_base + 0x7c00]                   ;取出GDT基址的低两个字节，放入ax
mov dx,[cs:gdt_base + 0x7c00 + 0x02]            ;取出GDT基址的高两个字节，放入dx
mov bx,16                                       ;因为要把GDT基址放入ds，所有要除16，bx作为除数
div bx                                          ;DX:AX除以16

mov ds,ax                                       ;GDT的基址放入dx寄存器
mov bx,dx                                       ;DX存储余数（偏移值），放入bx

;这四句，在内存里按字节写入段描述符
mov dword [bx + 0x00],0x00                      ;用0填充GDT的第0项的低4字节，GDT的第0项必须保留为空
mov dword [bx + 0x04],0x00                      ;用0填充GDT的第0项的高字节，GDT的第0项必须保留为空

mov dword [bx+0x08],0x8000ffff                  ;说明段从物理地址0x00008000开始，段的长度低16位是0xFFFF
mov dword [bx+0x0c],0x0040920b                  ;指定了基地址是0x00 0B 80 00
;后面lgdt会加载这个GDT到CPU，使保护模式可以用这一段描述符的段选择子去访问内存

mov word [cs:gdt_size + 0x7c00],15              ;定义了GDT的限长

lgdt [cs:gdt_size + 0x7c00]                     ;加载GDT到CPU

in al,0x92
or al,0000_0010B
out 0x92,al
                                                ;打开8086的A20地址线
cli 

mov eax,cr0
or eax,1
mov cr0,eax                                     ;开启保护模式的开关

mov cx,00000000000_01_000B                      ;就是让 CX 保存一个 段选择子，表示 “GDT 的第1个有效段，位于 Ring0
mov ds,cx
         mov byte [0x00],'P'
         mov byte [0x02],'r'
         mov byte [0x04],'o'
         mov byte [0x06],'t'
         mov byte [0x08],'e'
         mov byte [0x0a],'c'
         mov byte [0x0c],'t'
         mov byte [0x0e],' '
         mov byte [0x10],'m'
         mov byte [0x12],'o'
         mov byte [0x14],'d'
         mov byte [0x16],'e'
         mov byte [0x18],' '
         mov byte [0x1a],'O'
         mov byte [0x1c],'K'
         mov byte [0x1e],'.'

         hlt 

gdt_size dw 0
gdt_base dd 0x00007e00

times 510-($-$$) db 0
                 db 0x55,0xaa